#include"meta_stream.hpp"

#include<iostream>

#include"Algo.hpp"
using namespace meta_ios;

template<class str, class T>
struct str_field_member {
    T value;
    using type = T;

    template<class TL>
    static constexpr bool name_equal = std::is_same_v<
        to_exp_list_t<TL>,
        str
    >;

    template<static_str s>
    static constexpr bool name_is = name_equal<str_to_list<s>>;

    bool operator ==(const char* pstr)const {
        return std::strcmp((const char*)(to_exp_char_t<str>{}), pstr) == 0;
    }
};

template<static_str s>
auto field_str(auto v) -> str_field_member<str_to_list<s>, decltype(v)>
{
    return { v };
}

#include"aligned_field.hpp"

struct assigner {
    std::byte* data_ptr;
    template<class T> operator T() {
        return *(reinterpret_cast<T*>(data_ptr));
    }
    template<class T> assigner &operator=(T const& v){
        assert(data_ptr != nullptr);
        *reinterpret_cast<T*>(data_ptr) = v;
        return *this;
    }
};

template<class ...str, class ...Tys>
class static_aligned_field<str_field_member<str, Tys>...> : public static_aligned_field<Tys...>
{
public:
    static_aligned_field(str_field_member<str, Tys> const& ...val) :static_aligned_field<Tys...>(val.value...) {}
    assigner get(const char* name) {
        std::byte* ptr{ nullptr };
        meta_for<meta_getch, meta_istream<static_aligned_field>>::
            for_each(
                [this, &ptr]<class T>(T, const char* n) {
            if (typename T::to::type{} == n) {
                constexpr auto IDX = exp_size<static_aligned_field> -T::from::type::length - 1;
                ptr = reinterpret_cast<std::byte*> ( & (this->read<IDX>()));
            }
        }, name
            );
        return { ptr };
    }

    auto operator[](const char* name) {
        return get(name);
    }
};

int main() {
    static_aligned_field field{
        field_str<"a">(1),
        field_str<"b">(2.33)
    };

   // field["a"] = 3;
    field["b"] = 2.44;

    std::cout << field.read<1>() << std::endl;

    struct X {
        int a;
        double b;
    };

    std::cout << field.cast<X>().b << std::endl;

};
